using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace GP2D3D_Huiswerk2_RickBeijer_S1012261
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Huiswerk2Game : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphicsDeviceManager;
        SpriteBatch spriteBatch;
        private TimeSpan smallestTimeSpanPossible;
        private TimeSpan previousElapsedGameTime;
        private TimeSpan totalElapsedUpdateTime;
        private int updates;
        private int updatesPerSecond;
        private bool isKeyEscDown;
        private bool isMouseDown;
        private BasicEffect basicEffect;
        private TimeSpan totalElapsedDrawTime;
        private int draws;
        private int drawsPerSecond;
        private SpriteFont kootenayFont;

        public Huiswerk2Game()
        {
            graphicsDeviceManager = new GraphicsDeviceManager(this);
            graphicsDeviceManager.PreparingDeviceSettings += new EventHandler<PreparingDeviceSettingsEventArgs>(graphicsDeviceManager_PreparingDeviceSettings);
            Content.RootDirectory = "Content";
            IsFixedTimeStep = false;
            IsMouseVisible = true;

            //smallestTimeSpanPossible = new TimeSpan( 7500L );
            smallestTimeSpanPossible = new TimeSpan(0L); 
            previousElapsedGameTime = TimeSpan.MaxValue;
            totalElapsedUpdateTime = TimeSpan.Zero;
            updates = 0;
            updatesPerSecond = 0;
            isKeyEscDown = false;
            isMouseDown = false;
            totalElapsedDrawTime = TimeSpan.Zero;
            draws = 0;
            drawsPerSecond = 0;
        }

        protected void graphicsDeviceManager_PreparingDeviceSettings(object sender, PreparingDeviceSettingsEventArgs e)
        {
            e.GraphicsDeviceInformation.PresentationParameters.BackBufferWidth = 800;
            e.GraphicsDeviceInformation.PresentationParameters.BackBufferHeight = 600;
            e.GraphicsDeviceInformation.PresentationParameters.FullScreenRefreshRateInHz = 60;
            e.GraphicsDeviceInformation.PresentationParameters.IsFullScreen = true;
            e.GraphicsDeviceInformation.PresentationParameters.EnableAutoDepthStencil = true;
            e.GraphicsDeviceInformation.PresentationParameters.MultiSampleQuality = 0;
            e.GraphicsDeviceInformation.PresentationParameters.MultiSampleType = MultiSampleType.FourSamples;
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // Creates a world with x = 0 and y = 0 lying in the top left of the screen.
            basicEffect = new BasicEffect( GraphicsDevice, null );
            basicEffect.World = Matrix.Identity;
            basicEffect.View = new Matrix( 1.0f, 0.0f,  0.0f, 0.0f,
                                           0.0f, 1.0f,  0.0f, 0.0f,
                                           0.0f, 0.0f, -1.0f, 0.0f,
                                           0.0f, 0.0f,  0.0f, 1.0f );
            basicEffect.Projection = Matrix.CreateOrthographicOffCenter( 0,
                                                                         Window.ClientBounds.Width,
                                                                         Window.ClientBounds.Height,
                                                                         0,
                                                                         -10f,
                                                                         10f );
            
            PointList pointList = new PointList( this, basicEffect );
            Components.Add( pointList );
            Services.AddService( typeof(IPointList), pointList );

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            kootenayFont = Content.Load<SpriteFont>( "Kootenay" );

            FireAnt fireAnt = new FireAnt(this, spriteBatch, new Point(Window.ClientBounds.Width / 2, Window.ClientBounds.Height / 2));
            Components.Add(fireAnt);
            ProjectileList projectileList = new ProjectileList(this, spriteBatch);
            Components.Add(projectileList);
            Services.AddService(typeof(IProjectileList), projectileList);
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            totalElapsedUpdateTime = totalElapsedUpdateTime.Add( gameTime.ElapsedGameTime );
            updates++;

            if ( totalElapsedUpdateTime.Seconds >= 1 )
            {
                totalElapsedUpdateTime = TimeSpan.Zero;
                updatesPerSecond = updates;
                updates = 0;
            }

            KeyboardState keyboardState = Keyboard.GetState();

            if ( keyboardState.IsKeyUp( Keys.Escape ) && isKeyEscDown )
            {
                Exit();
            }

            isKeyEscDown = keyboardState.IsKeyDown( Keys.Escape );

            MouseState mouseState = Mouse.GetState();

            if (mouseState.LeftButton == ButtonState.Pressed)
            {
                ( (IPointList) Services.GetService( typeof(IPointList) ) ).Add( new Vector3( mouseState.X, mouseState.Y, 0 ),
                                                                                Color.DarkSalmon );
            }

            isMouseDown = mouseState.LeftButton == ButtonState.Pressed;

            // When the game is running faster than we want, set its update time as the target time.
            if (!IsFixedTimeStep)
            {
                if ( gameTime.ElapsedGameTime < previousElapsedGameTime )
                {
                    if ( gameTime.ElapsedGameTime.Ticks != 0 )
                    {
                        TargetElapsedTime = gameTime.ElapsedGameTime;
                        previousElapsedGameTime = TargetElapsedTime;
                    }
                }

                if (TargetElapsedTime <= smallestTimeSpanPossible)
                {
                    IsFixedTimeStep = true;
                    TargetElapsedTime = smallestTimeSpanPossible;
                }
            }

            base.Update( gameTime );
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            totalElapsedDrawTime = totalElapsedDrawTime.Add( gameTime.ElapsedGameTime );
            draws++;

            if ( totalElapsedDrawTime.Seconds >= 1 )
            {
                totalElapsedDrawTime = TimeSpan.Zero;
                drawsPerSecond = draws;
                draws = 0;
            }

            GraphicsDevice.Clear( Color.CornflowerBlue );

            spriteBatch.Begin();
            spriteBatch.DrawString( kootenayFont,
                                    "Elapsed Game Time: " + gameTime.ElapsedGameTime,
                                    new Vector2( 10, 10 ),
                                    Color.BlueViolet );
            spriteBatch.DrawString( kootenayFont,
                                    "Updates per Second: " + updatesPerSecond,
                                    new Vector2( 10, 30 ),
                                    Color.BlueViolet );
            spriteBatch.DrawString( kootenayFont,
                                    "Draws per Second: " + drawsPerSecond,
                                    new Vector2( 10, 50 ),
                                    Color.BlueViolet );
            spriteBatch.End();

            base.Draw( gameTime );
        }
    }
}